/*
RECCLI.C

The record application's client window and its components
*/


#include <p_std.h>
#include <p_sys.h>
#include <p_date.h>
#include <epoc.h>
#include <p_config.h>
#include <record.g>
#include <hwim.h>
#include <record.rsg>
#include <fonts.h>
#include <olib.h>

GLREF_D PR_RECWSERV * const w_ws;
GLREF_D PR_APPMAN * const w_am;
GLREF_D PR_RECENG * const receng;

#define TIMEBAR_HEIGHT 13

#define RECBUT_HIDE_DRAW  0
#define RECBUT_HIDE_HIDE  1
#define RECBUT_HIDE_CLEAR 2

#define RECBUT_HALF_WIDTH 34
#define RECBUT_HALF_HEIGHT 10
#define RECBUT_ASCENT 16
#define RECBUT_MARGIN 20

#define RECCLI_NBUTTONS 5
#define RECCLI_3BUT_MASK 0x7        /* 1st 3 buttons */
#define RECCLI_STOP_MASK 0x8        /* 4th button */
#define RECCLI_START_MASK 0x10      /* 5th button */

LOCAL_D UBYTE recbut_hide[RECCLI_NBUTTONS]=
    {RECBUT_HIDE_CLEAR,RECBUT_HIDE_HIDE,RECBUT_HIDE_CLEAR,RECBUT_HIDE_HIDE,RECBUT_HIDE_HIDE};

LOCAL_C TEXT *NextZTS(TEXT *str)
    {
    while (*str++);
    return(str);
    }

LOCAL_C VOID StartFRC(PR_TIMEBAR *self)
    {
    UWORD tick,mode;

    mode=E_FRC_REPEATING;
    tick=100;
    p_iow4(self->active.pcb,P_FSTART,&mode,&tick);
    }

LOCAL_C INT BarLength(PR_TIMEBAR *self)
    {
    INT width;

    width=self->timebar.rect.br.x-self->timebar.rect.tl.x-2;
    if (self->timebar.tenths0)
        width-=(UINT)((width*self->timebar.tenths)/self->timebar.tenths0);
    return(width);
    }

LOCAL_C VOID DrawBar(PR_TIMEBAR *self,INT border,INT createGC)
    {
    INT x1,x2;
    P_RECT r;

    x1=self->timebar.x;
    x2=BarLength(self);
    if (x2==x1 && self->timebar.visible && !border)
        return;
    if (createGC)
        gCreateTempGC0(self->timebar.wid);
    r=self->timebar.rect;
    if (!self->timebar.visible)
        {
        gClrRect(&r,G_TRMODE_CLR);
        goto exit;
        }
    if (border)
        gBorderRect(&r,W_BORD_CORNER_1);
    p_insrec(&r,1,1);
    if (x1>x2)
        {
        gClrRect(&r,G_TRMODE_CLR);
        x1=0;
        }
    self->timebar.x=x2;
    r.tl.x+=x1;
    r.br.x=r.tl.x+x2-x1;
    gFillPattern(&r,WS_BITMAP_GREY,G_TRMODE_REPL);
    exit:
    if (createGC)
        {
        gFreeTempGC();
        wFlush();
        }
    }

LOCAL_C VOID DrawButton(PR_RECBUT *self,INT state)
    {
    wDrawButton2(W_BUTTON_TYPE_2,&self->recbut.rect,&self->recbut.inlabel[0],state);
    }

LOCAL_C VOID PrintHeader(PR_RECCLI *self,INT y,TEXT *fmt,...)
    {
    INT len;
    TEXT bb[256];
    P_RECT rect;

    rect.tl.x=8;
    rect.tl.y=y;
    rect.br.x=rect.tl.x+self->reccli.width-16;
    rect.br.y=y+30;
    if (fmt==NULL)
        {
        gClrRect(&rect,G_TRMODE_CLR);
        return;
        }
    len=p_atob(&bb[0],fmt,&fmt+1);
    gPrintBoxText(&rect,20,G_TEXT_ALIGN_CENTRE,0,&bb[0],len);
    }

LOCAL_C VOID HideButtons(PR_RECCLI *self,INT mask)
/*
Set the hidden state of the buttons to hide depending on the bits in mask.
*/
    {
    INT i;

    for (i=0;i<RECCLI_NBUTTONS;i++,mask>>=1)
        self->reccli.recbut[i]->recbut.hide=(mask&1)?recbut_hide[i]:RECBUT_HIDE_DRAW;
    }

LOCAL_C VOID DrawWin(PR_RECCLI *self)
    {
    G_GC gc;

    gc.flags=G_GC_FLAG_BOTH_PLANES;
    gCreateTempGC(self->win.id,G_GC_MASK_GREY,&gc);
    p_send2(self,O_WN_DRAW);
    gFreeTempGC();
    }

LOCAL_C VOID PrintDuration(PR_RECCLI *self,TEXT *buf,ULONG tenths)
    {
    ULONG seconds;
    UINT secs;
    P_DAYSEC ds;
    P_DATE dt;

    seconds=tenths/10;
    if (seconds<60)
        {
        secs=(UINT)seconds;
        p_atos(buf,"%d.%d %s",secs,(UINT)tenths-10*secs,self->reccli.secs);
        return;
        }
    p_sttods(&seconds,&ds);
    p_dstodt(&ds,&dt);
    ds.day-=25567; /* base days at Jan 1 1970 */
    if (ds.day>0)
        { /* show number of days */
        p_atos(buf,"%ld  ",ds.day);
        buf+=p_slen(buf);
        }
    if (dt.hour>0 || ds.day>0)
        { /* show number of hours */
        p_atos(buf,"%02d%c",dt.hour,self->reccli.tsep);
        buf+=p_slen(buf);
        }
    p_atos(buf,"%02d%c%02d",dt.minute,self->reccli.tsep,dt.second);
    }

#pragma METHOD_CALL

METHOD VOID timebar_tb_draw(PR_TIMEBAR *self)
    {
    self->timebar.x=0;
    DrawBar(self,TRUE,FALSE);
    }

METHOD VOID timebar_ao_init(PR_TIMEBAR *self,INT wid,P_RECT *prect)
    {
    self->active.priority=PRIORITY_ACTIVE_REPEATER;
    p_send3(w_am,O_AM_ADD_TASK,self);
    self->timebar.wid=wid;
    self->timebar.rect=*prect;
    }

METHOD VOID timebar_ao_queue(PR_TIMEBAR *self)
    {
    p_ioc3(self->active.pcb,P_FREAD,&self->active.stat);
    self->active.isactive=TRUE;
    }

METHOD INT timebar_ao_run(PR_TIMEBAR *self)
    {
    if (self->active.stat<0)
        { /* possibly because the machine was switched off then on */
        StartFRC(self); /* restart the FRC */
        self->active.stat=0;
        }
    self->timebar.tenths-=self->active.stat;
    if (self->timebar.tenths<=0)
        {
        self->timebar.tenths=0; /* stops re-queue */
        p_close(self->active.pcb);
        self->active.pcb=NULL;
        }
    DrawBar(self,FALSE,TRUE);
    if (self->timebar.tenths)
        timebar_ao_queue(self);
    return(RUN_ACTIVE_USED);
    }

METHOD VOID timebar_tb_start(PR_TIMEBAR *self,ULONG *tenths)
    {
    self->timebar.tenths0=*tenths;
    self->timebar.tenths=self->timebar.tenths0;
    self->timebar.x=0;
    self->timebar.visible=TRUE;
    if (self->timebar.tenths<10 || p_open(&self->active.pcb,"FRC:",-1)<0)
        return;
    StartFRC(self);
    DrawBar(self,TRUE,TRUE);
    timebar_ao_queue(self);
    }

METHOD VOID timebar_tb_stop(PR_TIMEBAR *self)
    {
    p_send2(self,O_AO_CANCEL);
    self->timebar.visible=FALSE;
    p_close(self->active.pcb);
    self->active.pcb=NULL;
    }

METHOD VOID recbut_destroy(PR_RECBUT *self)
    {
    p_free(self->recbut.buttxt);
    p_supersend2(self,O_DESTROY);
    }

METHOD VOID recbut_rb_init(PR_RECBUT *self,INT wid,P_POINT *pc,INT rid)
    {
    self->recbut.wid=wid;
    self->recbut.rect.tl.x=pc->x-RECBUT_HALF_WIDTH;
    self->recbut.rect.br.x=pc->x+RECBUT_HALF_WIDTH;
    self->recbut.rect.tl.y=pc->y-RECBUT_HALF_HEIGHT;
    self->recbut.rect.br.y=pc->y+RECBUT_HALF_HEIGHT;
    hLoadResource(rid,&self->recbut.buttxt);
    self->recbut.inlabel=(TEXT *)(((WORD *)self->recbut.buttxt)+1);
    self->recbut.caption=NextZTS(self->recbut.inlabel);
    self->recbut.caplen=p_slen(self->recbut.caption);
    }

METHOD VOID recbut_rb_draw(PR_RECBUT *self)
    {
    P_RECT r;

    if (self->recbut.hide==RECBUT_HIDE_HIDE)
        return;
    r.tl.x=self->recbut.rect.tl.x-RECBUT_MARGIN;
    r.br.x=self->recbut.rect.br.x+RECBUT_MARGIN;
    r.br.y=self->recbut.rect.tl.y;
    r.tl.y=r.br.y-(2*RECBUT_HALF_HEIGHT);
    if (self->recbut.hide==RECBUT_HIDE_CLEAR)
        {
        gClrRect(&r,G_TRMODE_CLR);
        gClrRect(&self->recbut.rect,G_TRMODE_CLR);
        return;
        }
    DrawButton(self,0);
    gPrintBoxText(&r,RECBUT_ASCENT,G_TEXT_ALIGN_CENTRE,0,self->recbut.caption,self->recbut.caplen);
    }

METHOD VOID recbut_rb_depress(PR_RECBUT *self)
    {
    gCreateTempGC0(self->recbut.wid);
    DrawButton(self,2);
    wFlush();
    p_sleep(2L);
    DrawButton(self,0);
    wFlush();
    gFreeTempGC();
    }

METHOD VOID recbut_rb_hide(PR_RECBUT *self,INT hide)
    {
    self->recbut.hide=hide;
    }

METHOD VOID reccli_destroy(PR_RECCLI *self)
    {
    p_free(self->reccli.clitxt);
    p_supersend2(self,O_DESTROY);
    }

METHOD VOID reccli_wn_connect(PR_RECCLI *self,PR_WIN *par,UINT fields,W_WINDATA *pwd)
    {
    INT i,dx;
    P_POINT c;
    P_RECT rect;
    E_CONFIG config;

    p_getctd(&config);
    self->reccli.tsep=config.timeSeparator;
    self->reccli.width=pwd->extent.width;
    pwd->background=W_WIN_BACK_CLR|W_WIN_BACK_GREY_CLR;
    p_supersend5(self,O_WN_CONNECT,par,fields|W_WIN_BACKGROUND,pwd);
    hInitVis(self);
    p_send3(self,O_WN_EMPHASISE,TRUE);
    rect.tl.x=12;
    rect.br.x=self->reccli.width-rect.tl.x;
    rect.tl.y=74;
    rect.br.y=rect.tl.y+TIMEBAR_HEIGHT;
    self->reccli.timebar=f_newsend(CAT_RECORD_RECORD,C_TIMEBAR,O_AO_INIT,self->win.id,&rect);
    dx=(self->reccli.width-6)/6;
    c.y=130;
    for (i=0;i<RECCLI_NBUTTONS;i++)
        {
        c.x=3+dx+(((i<3)?i*dx:dx)<<1);
        self->reccli.recbut[i]=f_newsend(CAT_RECORD_RECORD,C_RECBUT,O_RB_INIT,self->win.id,&c,CLIBUT_REC_NEW+i);
        }
    HideButtons(self,RECCLI_STOP_MASK|RECCLI_START_MASK);
    hLoadResource(RECCLI_TEXT,&self->reccli.clitxt);
    self->reccli.secs=(TEXT *)(((WORD *)self->reccli.clitxt)+1);
    self->reccli.title=NextZTS(self->reccli.secs);
    self->reccli.sub=NextZTS(self->reccli.title);
    wValidateWin(self->win.id); /* saves screen flicker on startup */
    }

METHOD VOID reccli_wn_draw(PR_RECCLI *self)
    {
    INT i,len,y;
    WVEFILE_INFO info;
    TEXT name[16];
    TEXT duration[20],total[20];
    G_GC gc;

    p_supersend(self,O_WN_DRAW); /* draw border */
    p_send2(self->reccli.timebar,O_TB_DRAW); /* draw time bar */
    /* draw buttons */
    for (i=0;i<RECCLI_NBUTTONS;recbut_rb_draw(self->reccli.recbut[i++]));
    p_send3(receng,O_ENG_FILE_INFO,&info);
    *p_bcpy(&name[0],info.name,len=info.nmlen)=0;
    p_scap(&name[0]);
    if (*info.device!='M')
        {
        name[len++]='[';
        name[len++]=*info.device;
        name[len++]=']';
        }
    name[len]=0;
    gc.style=G_STY_BOLD;
    gc.font=FONT_ID_SWISS_16;
    gSetGC(0,G_GC_MASK_STYLE|G_GC_MASK_FONT,&gc);
    y=8;
    if (info.duration)
        {
        PrintDuration(self,&duration[0],(LONG)info.duration);
        /* %s   %s   %d Kbyte */
        PrintHeader(self,y,self->reccli.title,&name[0],&duration[0],(INT)(info.flen>>10));
        }
    else 
        PrintHeader(self,y,"%s",&name[0]); /* might be a % character in name[] */
    y=40;
    if (info.repeats<=1 && info.silence==0)
        {
        PrintHeader(self,y,NULL); /* clear rectangle */
        return;
        }
    gc.style=G_STY_NORMAL;
    gc.font=FONT_ID_SWISS_13;
    gSetGC(0,G_GC_MASK_STYLE|G_GC_MASK_FONT,&gc);
    PrintDuration(self,&duration[0],(LONG)info.silence);
    PrintDuration(self,&total[0],info.total);
    /* Repeats: %d    Trailing silence: %s    Total: %s */
    PrintHeader(self,y,self->reccli.sub,info.repeats,&duration[0],&total[0]);
    }

METHOD VOID reccli_cl_update(PR_RECCLI *self)
    {
    p_send2(self->reccli.timebar,O_TB_STOP);
    self->reccli.running=FALSE;
    w_ws->wserv.filter=NULL;
    wDisableKeyClick(FALSE);
    HideButtons(self,RECCLI_STOP_MASK|RECCLI_START_MASK);
    DrawWin(self);
    wFlush();
    }

METHOD VOID reccli_wn_key(PR_RECCLI *self,UINT keycode,UINT modifiers)
    {
    switch (keycode)
        {
    case W_KEY_TAB:
        recbut_rb_depress(self->reccli.recbut[0]);
        hWservComSend(O_COM_RECORD_NEW);
        break;
    case ' ':
        recbut_rb_depress(self->reccli.recbut[1]);
        hWservComSend(O_COM_RE_RECORD);
        break;
    case W_KEY_RETURN:
        recbut_rb_depress(self->reccli.recbut[2]);
        p_send2(receng,O_ENG_SOUND_PLAY);
        break;
        }
    }

METHOD INT reccli_cl_sound_filter(PR_RECCLI *self,UINT keycode,UINT modifiers)
    {
    if (keycode==W_KEY_ESCAPE)
        {
        p_send2(receng,O_ENG_SOUND_STOP);
        recbut_rb_depress(self->reccli.recbut[3]);
        }
    return(WN_KEY_CHANGED);
    }

METHOD INT reccli_cl_pause_filter(PR_RECCLI *self,UINT keycode,UINT modifiers)
/*
Waiting to record.
*/
    {
    if (keycode==W_KEY_ESCAPE)
        p_send3(receng,O_ENG_OPEN_FILE,NULL);
    else if (keycode==' ')
        {
        w_ws->wserv.filter=NULL;
        p_send3(receng,O_ENG_SOUND_RECORD,self->reccli.duration);
        }
    return(WN_KEY_CHANGED);
    }

METHOD VOID reccli_cl_begin_sound(PR_RECCLI *self,ULONG *tenths)
    {
    p_send3(self->reccli.timebar,O_TB_START,tenths);
    self->reccli.running=TRUE;
    w_ws->wserv.filter=(PR_WIN *)self;
    w_ws->wserv.filmethod=-O_CL_SOUND_FILTER;
    wDisableKeyClick(TRUE);
    HideButtons(self,RECCLI_3BUT_MASK|RECCLI_START_MASK);
    DrawWin(self);
    wFlush();
    }

METHOD VOID reccli_cl_pause(PR_RECCLI *self,UINT duration)
    {
    self->reccli.duration=duration;
    w_ws->wserv.filter=(PR_WIN *)self;
    w_ws->wserv.filmethod=-O_CL_PAUSE_FILTER;
    HideButtons(self,RECCLI_3BUT_MASK|RECCLI_STOP_MASK);
    DrawWin(self);
    wFlush();
    }

METHOD VOID recman_am_clean_up(PR_RECMAN *self,INT err,UBYTE *htask)
    {
    PR_RECCLI *cli;

    cli=(PR_RECCLI *)w_ws->wserv.cli;
    w_ws->wserv.filter=NULL;
    wDisableKeyClick(FALSE);
    p_send2(cli->reccli.timebar,O_TB_STOP);
    p_supersend4(self,O_AM_CLEAN_UP,err,htask);
    p_send3(receng,O_ENG_OPEN_FILE,NULL);
    }
